﻿#ifndef TESTCASEFORM_H
#define TESTCASEFORM_H

#include <QWidget>
#include <QStyledItemDelegate>
#include <QFutureWatcher>

namespace Ui {
class TestCaseForm;
}

struct TParamValue
{
    int type;
    QString inputValue;
    QString expectedValue;
    QString returnedValue;
    QString compResult;

    TParamValue()
    {
        type = 0;
    }
};
Q_DECLARE_METATYPE(TParamValue)
Q_DECLARE_TYPEINFO(TParamValue, Q_COMPLEX_TYPE);

QDataStream &operator<< (QDataStream&, const TParamValue&);
QDataStream &operator>> (QDataStream&, TParamValue&);

typedef QMap<QString, TParamValue> TMethodParams;
typedef QMap<int, TMethodParams> TMethods;

class QStandardItemModel;
class QStandardItem;

class TestCaseForm : public QWidget
{
    Q_OBJECT

public:
    explicit TestCaseForm(QWidget *parent = nullptr);
    ~TestCaseForm();

    QSize sizeHint() const;

    QAction* windowMenuAction() const { return action; }

    bool newFile(const QString& moduleName, const QStringList& methodSignatures);
    bool save();
    bool saveAs();

    static TestCaseForm* open(QWidget* parent);
    static TestCaseForm* openFile(const QString& fileName, QWidget* parent = 0);

    friend QDataStream &operator>>(QDataStream&, TestCaseForm&);
    friend QDataStream &operator<<(QDataStream&, TestCaseForm&);

signals:
    void moduleNameChanged();
    void aMethodTestBegin(bool& isContinue);
    void aMethodTestFinished(const QVariantList& paramsRetVal, int& result, int timeUsed);
    void setCurrentMethod(int index);
    void testPause(bool isPaused);

public slots:
    void on_moduleNameChanged();
    void on_tvMethods_currentRowChanged(const QModelIndex &current, const QModelIndex &previous);
    void on_pbAddMethod_clicked();
    void on_pbDelMethod_clicked();
    void on_pbMoveUpMethod_clicked();
    void on_pbMoveDownMethod_clicked();
    void on_paramTable_itemChanged(QStandardItem *item);
    void on_paramTypeCmb_currentIndexChanged(int index);
    void on_pbStart_clicked();
    void on_pbStop_clicked();
    void on_pbStep_clicked();
    void on_aMethodTestBegin(bool& isContinue);
    void on_aMethodTestFinished(const QVariantList& paramsRetVal, int& result, int timeUsed);
    void on_setCurrentMethod(int index);
    void on_testFinished();
    void on_testPause(bool isPaused);
    void on_pbClear_clicked();
    void on_pbExport_clicked();

protected:
    void closeEvent(QCloseEvent *event);

private:
    bool okToContinue();
    bool saveFile(const QString& fileName);
    void setCurrentFile(const QString& fileName);
    bool readFile(const QString& fileName);
    bool writeFile(const QString& fileName);
    QString strippedName(const QString& fullFileName);
    void enableControls(bool enabled);
    void setItemCheckable(QStandardItem* item);

    bool testOneMethod(QObject* testObj, const QString& methodName);

    Ui::TestCaseForm *ui;
    QStandardItemModel* modelMethods;
    QStandardItemModel* modelParams;
    QString moduleName;
    QAction* action;
    QString curFile;
    bool isUntitled;
    TMethods methods;
    QFutureWatcher<void> watcher;
    volatile bool isPaused;
    QObject* testObj;

    class MethodsTableDelegate: public QStyledItemDelegate {
    public:
        MethodsTableDelegate(QObject *parent = Q_NULLPTR): QStyledItemDelegate(parent) {}
        virtual ~MethodsTableDelegate() {}

        void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
    };

    class ParamsTableDelegate: public QStyledItemDelegate {
    public:
        ParamsTableDelegate(QObject *parent = Q_NULLPTR): QStyledItemDelegate(parent) { parentForm = qobject_cast<TestCaseForm*>(parent); }
        virtual ~ParamsTableDelegate() {}

        void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
        QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const;
        void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const;
        void setEditorData(QWidget *editor, const QModelIndex &index) const;
        void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const;

    private:
        TestCaseForm* parentForm;
    };
};

#endif // TESTCASEFORM_H
